import { onMounted, ref } from "vue";
// @ts-ignore
import { getOffset } from "@/utils/dom";
import scratchArea from "../images/scratch_area.png";

export function useCanvas(props, { emit }) {
  let isFinish = false;
  let isCanMove = false;
  const canvasRef = ref<HTMLCanvasElement>(null);
  const cScratchRef = ref<HTMLDivElement>(null);

  const initCanvas = () => {
    if (!canvasRef.value) {
      throw new Error("canvasRef 为 null");
    }

    isFinish = false;

    const ctx = canvasRef.value.getContext("2d");
    canvasRef.value.height = cScratchRef.value.offsetHeight;
    canvasRef.value.width = cScratchRef.value.offsetWidth;

    // 初始化画布
    canvasRef.value.classList.remove("disappear");
    ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height);
    ctx.globalCompositeOperation = "source-over";
    // 绘制
    ctx.beginPath();
    const img = new Image();
    img.onload = () => {
      ctx.drawImage(img, 0, 0, canvasRef.value.width, canvasRef.value.height);
    };
    img.src = scratchArea;
    // 背景色默认为黑色，所以填充一个透明色不然有边角
    ctx.fillStyle = "transparent";
    ctx.fillRect(0, 0, canvasRef.value.width, canvasRef.value.height);
    ctx.closePath();

    return { ctx };
  };

  const handleTouchStart = (ctx, oLeft, oTop) => (event) => {
    emit("start");
    if (props.disabled) {
      emit("trigger-disabled");
      return;
    }

    isCanMove = true;

    // 画笔粗细
    ctx.lineWidth = props.lineWidth;
    // 设置组合效果---关键代码
    ctx.globalCompositeOperation = "destination-out";
    // 移动画笔原点
    ctx.moveTo(event.touches[0].pageX - oLeft, event.touches[0].pageY - oTop);

    // 防止抖动
    event.preventDefault();
  };

  const handleTouchMove = (ctx, oLeft, oTop) => (event) => {
    if (!isCanMove) return;

    /* 根据手指移动画线，使之变透明 */
    ctx.lineTo(event.touches[0].pageX - oLeft, event.touches[0].pageY - oTop);
    // 填充
    ctx.stroke();
  };

  const handleTouchEnd = (ctx) => () => {
    if (isFinish || props.disabled) return;

    isCanMove = false;

    // 获取imageData对象
    const imageDate = ctx.getImageData(
      0,
      0,
      canvasRef.value.width,
      canvasRef.value.height
    );
    const allPX = imageDate.width * imageDate.height;

    let iNum = 0; //记录刮开的像素点个数[透明度为0的像素点]

    for (let i = 0; i < allPX; i++) {
      // 透明度如果为0
      if (imageDate.data[i * 4 + 3] === 0) {
        iNum++;
      }
    }

    // 非要定义一个变量，否则报错
    const fp: number = props.finishProportion;
    // 结束
    if (iNum >= allPX * fp) {
      // disappear里面写了缓慢清除的css3动画效果
      canvasRef.value.classList.add("disappear");
      isFinish = true;

      emit("finish");
    }
  };

  onMounted(() => {
    // 必须在图片加载完成后在绑定事件，否则 getOffset 拿到的数据不准确
    // window.onload 事件有局限性，有时候监听不到
    allImagesLoaded().finally(bindEvents);
  });

  function allImagesLoaded() {
    // 性能有待优化，应该获取刮刮卡上方的元素即可
    const images = document.querySelectorAll("img");
    const picsAll = Array.from(images).map(
      (img) =>
        new Promise((resolve, reject) => {
          img.onload = () => resolve("img load success");
          img.onerror = () => reject("img load error");
        })
    );
    return Promise.all(picsAll);
  }

  function bindEvents() {
    const { ctx } = initCanvas();

    /* 画布偏移量 */
    const [oLeft, oTop] = getOffset(canvasRef.value);

    canvasRef.value.addEventListener(
      "touchstart",
      handleTouchStart(ctx, oLeft, oTop),
      false
    );

    canvasRef.value.addEventListener(
      "touchmove",
      handleTouchMove(ctx, oLeft, oTop),
      false
    );

    canvasRef.value.addEventListener("touchend", handleTouchEnd(ctx), false);
  }

  // 获取是否已经刮开了
  function getIsFinish() {
    return isFinish;
  }

  return {
    resetCanvas: initCanvas,
    canvasRef,
    cScratchRef,
    getIsFinish,
  };
}
